#pragma once
#include "Mutex.hpp"
#include <iostream>
#include <filesystem>
#include <fstream>

namespace LogMoudule
{
    using namespace ThreadMoudle;

    // 默认路径和⽇志名称
    const std::string defaultpath = "./log/";
    const std::string defaultname = "log.txt";

    // ⽇志等级
    enum class LogLevel
    {
        DEBUG = 1,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    // 策略模式，策略接口
    class LogStrategy
    {
    public:
        virtual ~LogStrategy() = default;
        virtual void SynLog(const std::string &message) = 0; // 刷新策略不同，由基类实现
    };

    // 1. 控制台日志策略
    class ConsoleLogStrategy : public LogStrategy
    {
    public:
        void SynLog(const std::string &message) override
        {
            LockGuard LockGuard(_mutex);
            std::cerr << message << std::endl;
        }

    private:
        Mutex _mutex; // 显⽰器也是临界资源，保证输出线程安全
    };

    // 2. 文件日志策略
    class FileLogStrategy : public LogStrategy
    {
    public:
        FileLogStrategy(const std::string &filename = defaultname, const std::string &filepath = defaultpath)
        : _logpath(filepath), _logname(filename)
        {
            LockGuard lockgaurd(_mutex);
            if (std::filesystem::exists(_logpath))
                return;
            try
            {
                std::filesystem::create_directories(_logpath);
            }
            catch (const std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << '\n';
            }
        }
        void SynLog(const std::string &message) override
        {
            LockGuard LockGuard(_mutex);
            std::string loginfo = _logpath + _logname;
            std::ofstream out(loginfo.c_str(), std::ios::app); // 日志写入为追加方式
            if (!out.is_open())
            {
                return;
            }
            out << message << "\n";
            out.close();
        }

    private:
        std::string _logpath;
        std::string _logname;

        Mutex _mutex; // 显⽰器也是临界资源，保证输出线程安全
    };

    class Logger
    {
    private:

        static std::string GetCurrTime()
        {
            time_t t = time(0);
            struct tm curr;
            localtime_r(&t, &curr);
            char timebuffer[64];
            snprintf(timebuffer, sizeof(timebuffer),
                     "%4d-%02d-%02d %02d:%02d:%02d",
                     curr.tm_year + 1900, curr.tm_mon + 1, curr.tm_mday,
                     curr.tm_hour, curr.tm_min, curr.tm_sec);
            return timebuffer;
        }

    public:

        // 内部类，实现RAII⻛格的⽇志格式化和刷新
        // 这个LogMessage，表⽰⼀条完整的⽇志对
        class LogMessage
        {
        private:
            std::string LogLevelToString()
            {
                switch (_type)
                {
                case LogLevel::DEBUG:
                    return "DEBUG" ;
                    break;
                case LogLevel::INFO:
                    return "INFO" ;
                    break;
                case LogLevel::WARNING:
                    return "WARNING" ;
                    break;
                case LogLevel::ERROR:
                    return "ERROR" ;
                    break;
                case LogLevel::FATAL:
                    return "FATAL" ;
                    break;
                default:
                    return "UNKNOWN_TYPE";
                    break;
                }
            }

        public:
            LogMessage(LogLevel type, std::string filename, int line, const Logger &logger)
            : _type(type), _pid(getpid()), _filename(filename), _logger(logger), _line(line), _curr_time(GetCurrTime())
            {
                // std::cerr<<"LogMessage begin"<<"\n";
                std::stringstream ss;
                ss<< "[" << _curr_time << "] "
                << "[" << LogLevelToString() << "] "
                << "[" << _pid << "] "
                << "[" << _filename << "] "
                << "[" << _line << "] ";
                _loginfo = ss.str();
            }
            // 重载<<支持输出 string 、 int 、 
            template<typename T>
            LogMessage& operator <<(T info)
            {
                // std::cerr<<"LogMessage operator << begin _loginfo:"<<_loginfo<<"\n";
                std::stringstream ss;
                ss << info;
                _loginfo+=ss.str();
                return *this; // 返回当前LogMessage对象，方便下次继续进行<<
            }
            ~LogMessage()
            {
                //利用对象析构时输出
                if(_logger._strategy)
                {
                    _logger._strategy->SynLog(_loginfo);
                }      
            }
        private: 
            LogLevel _type;
            std::string _curr_time;
            pid_t _pid;
            std::string _filename;
            int _line;
            const Logger &_logger;
            std::string _loginfo;
        };
        void EnableFileLog()
        {
            _strategy = std::make_unique<FileLogStrategy>();
        }
        void EnableConsoleLog()
        {
            _strategy = std::make_unique<ConsoleLogStrategy>();
        }

        LogMessage operator()(LogLevel type,const std::string& filename,const int& line)
        {
            return LogMessage(type,filename,line,*this);
        }

    private:
        std::unique_ptr<LogStrategy> _strategy = std::make_unique<ConsoleLogStrategy>();
    } logger;


#define LOG(type) logger(type,__FILE__,__LINE__)
#define ENABLE_CONSOLE_LOG() logger.EnableConsoleLog()
#define ENABLE_FILE_LOG() logger.EnableFileLog()




}